[Spring-plus] 컴포넌트 스캔이란 (Spring service, controllor, Repository)
🙂

[Spring-plus] 컴포넌트 스캔이란 (Spring service, controllor, Repository)

Lecture
Framework
태그
dev
spring
public
완성
Y
생성일
Mar 17, 2024 01:34 PM
LectureName
Spring

1. 스프링 빈을 등록하는 방법

  • 수동 설정
  • 자동 설정 ( 컴포넌트 스캔)
 

2. 컴포넌트 스캔이란?

의미
빈을 설정하고, 의존성을 주입하는 것을 일일히 다 설정하는 것은 매우 어려운 일이다. 그래서 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다.
 
방법
@Component, @ComponentScan, @Autowired를 사용하여 자동으로 빈을 등록하고 빈을 찾고 의존성을 주입시킨다
 
예제
  1. 새로운 AppConfig
package com.hello.core; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @Configuration @ComponentScan( excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) //뭘 뺄껀지 ) public class AutoAppConfig { }
  • 설정 파일은 똑같다.
  • 하지만 이제는 ComponentScan이라는 어노테이션을 사용한다.
  • 해당 어노테이션 안에는 다양한 설정을 할 수 있다. ( 예외할 Component 설정 등 )
  • Configuration도 @Component 어노테이션이 붙어 있다.
 
 
  1. @Component 어노테이션
@Component public class MemberServiceImpl implements MemberService{ private MemberRepository memberRepository; //생성자를 통한 의존성 주입. @Autowired public MemberServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Override public void join(Member member) { memberRepository.save(member); } @Override public Member findMember(Long memberId) { return memberRepository.findById(memberId); } //for test public MemberRepository getMemberRepository(){ return memberRepository; } }
  • 빈으로 등록하고 싶은 소스코드에 @Component를 붙인다.
  • @Autowired같은 경우 해당 빈에 의존성 주입을 할 때 사용한다.
  • 이때 빈 이름은 앞글자만 소문자를 사용하고 나머지는 클래스와 같다.
  • 만약 직접 지정하고 싶으면 @Component(”memberService2”) 형태로 지정한다.
 
 

3. 컴포넌트 스캔의 탐색 위치

컴포넌트 스캔은 기본적으로 모든 패키지를 순회하며 @Component가 붙은 클래스들을 탐색한다. 너무 비효율적이다
@Configuration @ComponentScan( basePackages = "com.hello.core.member", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) ) public class AutoAppConfig2 { }
  • 이처럼 ComponentScan 어노테이션 안에 basePackages를 등록하면 탐색 기본 위치를 지정할 수 있다. 지정하지 않으면 @ComponentScan 어노테이션이 붙은 패키지부터 하위 패키지까지 순회하며 찾게 된다.
  • 하지만 기본적으로 패키지 위치를 지정하지 않고 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것이 좋다.
 
 

4. 기본적으로 컴포넌트가 붙여져 있는 경우

Controller
스프링 mvc 컨트롤러에서 사용한다.
  • 스프링 MVC 컨트롤러로 인식한다.
 
Service
스프링 비즈니스 로직에서 서비스 파트에서 사용한다.
  • 하지만 별 기능은 없고 해당 클래스가 서비스라는 것만 명시한다고 보면 된다.
 
Repository
스프링 데이터 접근 계층에서 사용한다.
  • 데이터 계층의 Exception을 스프링 Exception으로 변환해준다.
 
Configuration
스프링 설정 정보를 인식하고, 스프링 빈이 싱글톤을 유지하도록 추가 처리를 한다.
 
 

5. 컴포넌트 스캔 필터

컴포넌트 스캔 시 어노테이션을 생성해서 필터링을 하고자 하는 빈과 하지 말아야 할 빈을 분리할 수 있다.
 
예제
  1. Class MyIncludeComponent
import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyIncludeComponent { }
  1. Class MyExcludeComponent
package com.hello.core.component.filter; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyExcludeComponent { }
 
  1. 컴포넌트 스캔에 등록될 빈들
package com.hello.core.component.filter; @MyIncludeComponent public class BeanA { } @MyExcludeComponent public class BeanB { }
  • 두개는 다른 클래스에 있어야 하지만 편의상 자료에는 한곳에 몰아두었다.
 
  1. 테스트
public class ComponentFilterAppConfigTest { @Test void filterScan() { ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class); BeanA beanA = ac.getBean("beanA", BeanA.class); assertThat(beanA).isNotNull(); assertThrows( NoSuchBeanDefinitionException.class, () -> ac.getBean("beanB", BeanB.class)); } @Configuration @ComponentScan( includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class), excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class) ) static class ComponentFilterAppConfig { } }
  • 컴포넌트 스캔 이후 Bean을 가져오는 코드이다.
  • Bean A같은 경우 IncludeFilters에 등록되어 있어 스캔에 성공하지만
  • Bean B같은 경우 excludeFilter에 등록되어 있어 스캔되지 않는다.
 
필터 타입
필터에는 여러가지 옵션이 있다.
  • ANNOTATION
→ 기본값이며 어노테이션을 인식해서 작동한다.
  • ASSIGNABLE_TYPE
→ 지정한 타입과 자식 타입을 인식하여 작동한다.
 
이외에도
  • REGEX
  • CUSTOM
  • ASPECTJ
등 옵션이 존재한다.
 
 

6. 빈 중복 등록과 충돌

앞서서 빈 등록에는 자동 빈 등록과 수동 빈 등록이 있다고 말했다. 만약 빈 등록 과정에서 빈 등록이 충돌 나면 어떻게 될까?
 
자동 빈 등록 vs 자동 빈 등록
  • 컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 이름이 같은 경우 오류를 발생시킨다.
 
수동 빈 등록 vs 자동 빈 등록
  • 만약 수동 빈 등록과 자동 빈 등록이 충돌나면 수동 빈 등록이 오버라이딩 하게 된다. 하지만 매우 좋지 않은 방법임으로, 스프링은 최근에 오류가 나는 방향으로 기본값을 바꾸었다고 한다.
 
 
기본 Docker 명령어